package pl.edu.agh.voronoi;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.TreeSet;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import megamu.mesh.Hull;
import megamu.mesh.MPolygon;
import megamu.mesh.Voronoi;
import megamu.mesh.Voronoi.CrossPoints;
import megamu.mesh.Voronoi.PointReference;
import pl.edu.agh.hypergraph.CFAH;
import pl.edu.agh.lasil.driver.VDriver;
import pl.edu.agh.solid.Solid;

public class DisplayApp extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = 6464660158014689949L;
	private JPanel contentPane;
	private final ButtonGroup buttonGroup = new ButtonGroup();

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					DisplayApp frame = new DisplayApp();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	public class CompositePanel extends JPanel {

		private static final long serialVersionUID = 4512406492283069075L;

		GreenPanel green = new GreenPanel();

		public CompositePanel() {
			setLayout(null);

			green.setBounds(0, 0, 700, 600);

			green.setBackground(Color.BLACK);

			add(green);

		}

	}

	class GreenPanel extends JPanel {
		private static final long serialVersionUID = 1961213628206708853L;

		@Override
		public void paint(Graphics g) {

			// super.paint(g);

			// wypełniam figury Voronoia

			g.setColor(Color.BLUE);
			VDriver d = new VDriver();
			ArrayList<Solid> backgroundSolids = new ArrayList<>();
			HashMap<Integer, Solid> int2solid = new HashMap<>();
			CFAH G = new CFAH();

			for (int i = 0; i < d.myVoronoi.getRegions().length; i++) {

				MPolygon region = d.myVoronoi.getRegions()[i];

				if (fitViewport(region)) {

					Solid s = Solid.elevate(region.getCoords());
					backgroundSolids.add(s);
					int2solid.put(i, s);
					G.addVertex(s);

					fillRegion(g, region);
				}

			}

			// wypełniam obszary skrzyżowań

			CrossPoints cp = d.myVoronoi.crossPoints;

			g.setColor(Color.RED);
			for (int j = 0; j < cp.size(); j++) {

				ArrayList<PointReference> prl = cp
						.get(cp.keySet().toArray()[j]);
				boolean contin = true;
				for (PointReference pr : prl) {
					if (!fitViewport(pr, d.myVoronoi)) {
						contin = false;
						break;
					}
				}

				if (contin) {

					float[][] crossArea = new float[prl.size()][2];
					int m = 0;

					for (PointReference pr : prl) {

						int i = pr.regionNumber;
						int k = pr.numberOfPointInRegion;

						float x = d.myVoronoi.getRegions()[i].getCoords()[k][0];
						float y = d.myVoronoi.getRegions()[i].getCoords()[k][1];

						crossArea[m][0] = x;
						crossArea[m++][1] = y;

					}

					Hull h = new Hull(crossArea);

					Solid s = Solid.elevate(h.getRegion().getCoords());
					backgroundSolids.add(s);
					G.addVertex(s);

					for (PointReference pr : prl) {

						int i = pr.regionNumber;
						Solid tmp = int2solid.get(i);
						if (tmp != null)
							G.addEdge(tmp, s, "Skrzyżowanie");

					}

					fillRegion(g, h.getRegion());

				}
			}

			// wypełniam obszary ulic czyli prostoktąty rozpiete między
			// poszczególnymi
			// pomniejszonymi figurami Voronoia

			g.setColor(Color.YELLOW);

			int N = d.myVoronoi.getRegions().length;

			for (int i = 0; i < N; i++) {

				HashMap<Integer, ArrayList<String>> adj = d.myVoronoi
						.getAdjacentRegions(i);

				if (adj.isEmpty())
					continue;

				for (int j : adj.keySet()) {

					float[][] street = d.myVoronoi.getLinkingPoints(i, j,
							adj.get(j));

					if (!fitViewport(street))
						continue;
					Hull h = new Hull(street);

					Solid s = Solid.elevate(h.getRegion().getCoords());
					backgroundSolids.add(s);

					Solid tmp = int2solid.get(i);
					if (tmp != null)
						G.addEdge(s, tmp, "ul1");

					tmp = int2solid.get(j);
					if (tmp != null)
						G.addEdge(s, tmp, "ul2");

					fillRegion(g, h.getRegion());

				}

			}

			System.out.println("Number of generated solids: "
					+ backgroundSolids.size());
			System.out.println("CFAH stats : |V| = " + G.getVertexCount()
					+ ", |E| = " + G.getEdgeCount() + ", |E|/|V| = "
					+ (float) G.getEdgeCount() / G.getVertexCount());

		}

	}

	private boolean fitViewport(PointReference pr, Voronoi myVoronoi) {

		int i = pr.regionNumber;
		int k = pr.numberOfPointInRegion;

		int x = (int) myVoronoi.getRegion(i).getCoords()[k][0];
		int y = (int) myVoronoi.getRegion(i).getCoords()[k][1];

		if (x < 0 || y < 0 || x + 20 >= getWidth() || y + 120 >= getHeight())
			return false;

		return true;
	}

	private void drawRegion(Graphics g, MPolygon coor) {

		for (int k = 0; k < coor.count(); k++) {

			g.drawLine((int) coor.getCoords()[k][0],
					(int) coor.getCoords()[k][1],
					(int) coor.getCoords()[(k + 1) % coor.count()][0],
					(int) coor.getCoords()[(k + 1) % coor.count()][1]);
		}

	}

	private void fillRegion(Graphics g, MPolygon coor) {

		g.fillPolygon(coor.getPolygon());

	}

	private boolean fitViewport(float[][] coor) {

		for (int k = 0; k < coor.length; k++) {

			float x = coor[k][0];
			float y = coor[k][1];

			if (x < 0 || y < 0 || x + 20 >= getWidth()
					|| y + 120 >= getHeight())
				return false;
		}

		return true;
	}

	private boolean fitViewport(MPolygon coor) {

		for (int k = 0; k < coor.count(); k++) {

			float x = coor.getCoords()[k][0];
			float y = coor.getCoords()[k][1];

			if (x < 0 || y < 0 || x + 20 >= getWidth()
					|| y + 120 >= getHeight())
				return false;
		}

		return true;
	}

	/**
	 * Create the frame.
	 */
	public DisplayApp() {
		setTitle("Voronoi 0.1");
		// setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		// setBounds(100, 100, 450, 300);
		// contentPane = new CompositePanel();//JPanel();
		// contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		// contentPane.setLayout(new BorderLayout(0, 0));
		// setContentPane(contentPane);

		contentPane = new CompositePanel();
		// JFrame j = new JFrame();
		// j.setSize(300, 700);

		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(0, 0, 700, 600);

		setContentPane(contentPane);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		// setContentPane(new MyComponent());

		JButton btnVoronoiGen = new JButton("Voronoi Gen & Stretch");
		btnVoronoiGen.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {

				// (new MyComponent());
				// ((MyCanvas)getContentPane().getComponent(0)).p

				System.out.println("koko");

			}
		});
		buttonGroup.add(btnVoronoiGen);
		contentPane.add(btnVoronoiGen, BorderLayout.NORTH);
	}

}
